// Copyright 2022 a.o.smith ALL Rights Reserved
package com.liuxinlong.modules.assets.service.impl;

import com.liuxinlong.common.ExcelData;
import com.liuxinlong.constant.ThreadLocalConstants;
import com.liuxinlong.modules.assets.service.AssetsSpreadService;
import com.liuxinlong.modules.dao.AssetsBudgetYearDao;
import com.liuxinlong.modules.dao.AssetsDao;
import com.liuxinlong.modules.dao.AssetsDepartmentDao;
import com.liuxinlong.modules.dao.AssetsExpenseBudgetDao;
import com.liuxinlong.modules.dao.AssetsExpenseDao;
import com.liuxinlong.modules.dao.AssetsExpenseYearBudgetDao;
import com.liuxinlong.modules.dao.AssetsOrderDao;
import com.liuxinlong.modules.dao.AssetsOrderPayDao;
import com.liuxinlong.modules.dao.AssetsProjectDao;
import com.liuxinlong.modules.dao.AssetsStatisticsDao;
import com.liuxinlong.modules.dao.PatentDepartmentDao;
import com.liuxinlong.modules.dao.PatentDepartmentSpecialDao;
import com.liuxinlong.modules.dao.RoleDao;
import com.liuxinlong.modules.dao.UserRoleRelationDao;
import com.liuxinlong.modules.entity.Assets;
import com.liuxinlong.modules.entity.AssetsBudgetYear;
import com.liuxinlong.modules.entity.AssetsProject;
import com.liuxinlong.modules.entity.AssetsStatistics;
import com.liuxinlong.modules.entity.ExpenseBudget;
import com.liuxinlong.modules.entity.ExpenseOrder;
import com.liuxinlong.modules.entity.ExpenseYearBudget;
import com.liuxinlong.modules.entity.PatentDepartment;
import com.liuxinlong.modules.entity.PatentDepartmentSpecial;
import com.liuxinlong.modules.entity.User;
import com.liuxinlong.modules.entity.UserRole;
import com.liuxinlong.modules.entity.UserRoleRelation;
import com.liuxinlong.utils.DecimalUtils;
import com.liuxinlong.utils.ExcelUtils;
import com.liuxinlong.utils.ObjectUtils;
import com.liuxinlong.utils.ThreadlocalUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 固资预算业务接口层实现
 *
 * @author liuxinlong@hotwater.com.cn
 * @version 1.0.0
 * @since 2023-10-27
 */
@Service
@Slf4j
public class AssetsSpreadServiceImpl implements AssetsSpreadService {

    @Autowired
    private AssetsBudgetYearDao assetsBudgetYearDao;

    @Autowired
    private AssetsDao assetsDao;

    @Autowired
    private AssetsOrderDao assetsOrderDao;

    @Autowired
    private AssetsOrderPayDao assetsOrderPayDao;

    @Autowired
    private AssetsStatisticsDao assetsStatisticsDao;

    @Autowired
    private PatentDepartmentDao patentDepartmentDao;

    @Autowired
    private RoleDao roleDao;

    @Autowired
    private UserRoleRelationDao userRoleRelationDao;

    @Autowired
    private PatentDepartmentSpecialDao patentDepartmentSpecialDao;

    @Autowired
    private AssetsExpenseBudgetDao assetsExpenseBudgetDao;

    @Autowired
    private AssetsExpenseYearBudgetDao assetsExpenseYearBudgetDao;

    @Autowired
    private AssetsExpenseDao assetsExpenseDao;

    @Autowired
    private AssetsDepartmentDao assetsDepartmentDao;

    @Autowired
    private AssetsProjectDao assetsProjectDao;


    @Override
    public Map<String, Object> getAssetsDashboard(Map<String, Object> queryParam, int type) {
        Map<String, Object> dataMap = new HashMap<>();
        String currentYear = (String) queryParam.get("year");
        User currentUser = (User) ThreadlocalUtils.getCache(ThreadLocalConstants.USER_INFO);
        String userId = currentUser.getId();
        List<UserRoleRelation> userRoleRelationList = userRoleRelationDao.queryRelationByUserId(userId);
        UserRole highRole = roleDao.getRoleBySn("J020");
        List<UserRoleRelation> existHighList;
        if (ObjectUtils.isEmpty(highRole)) {
            existHighList = new ArrayList<>();
        } else {
            existHighList = userRoleRelationList.stream().filter(relation -> StringUtils.equals(relation.getRoleId(), highRole.getId())).collect(Collectors.toList());
        }
        dataMap.put("highPermission", !existHighList.isEmpty());
        UserRole manageRole = roleDao.getRoleBySn("J021");
        List<UserRoleRelation> existList;
        if (ObjectUtils.isEmpty(manageRole)) {
            existList = new ArrayList<>();
        } else {
            existList = userRoleRelationList.stream().filter(relation -> StringUtils.equals(relation.getRoleId(), manageRole.getId())).collect(Collectors.toList());
        }
        dataMap.put("managePermission", !existList.isEmpty());
        UserRole superManageRole = roleDao.getRoleBySn("J022");
        List<UserRoleRelation> existSuperList;
        if (ObjectUtils.isEmpty(superManageRole)) {
            existSuperList = new ArrayList<>();
        } else {
            existSuperList = userRoleRelationList.stream().filter(relation -> StringUtils.equals(relation.getRoleId(), superManageRole.getId())).collect(Collectors.toList());
        }
        dataMap.put("superPermission", !existSuperList.isEmpty());
        boolean depManage = false;
        List<PatentDepartment> departmentList = patentDepartmentDao.getDepartmentByManager(userId);
        if (!ObjectUtils.isEmpty(departmentList)) {
            depManage = true;
            List<String> depList = departmentList.stream().map(PatentDepartment::getId).collect(Collectors.toList());
            queryParam.put("manageDepartment", depList);
        }
        PatentDepartmentSpecial special = patentDepartmentSpecialDao.getDepartmentSpecialById(userId);
        if (!ObjectUtils.isEmpty(special)) {
            depManage = true;
            if (queryParam.containsKey("manageDepartment")) {
                List<String> depList = (List<String>) queryParam.get("manageDepartment");
                List<String> allList = new ArrayList<>();
                allList.addAll(depList);
                allList.addAll(Arrays.asList(special.getBranch().split(",")));
                queryParam.put("manageDepartment", allList);
            } else {
                List<String> allList = Arrays.asList(special.getBranch().split(","));
                queryParam.put("manageDepartment", allList);
            }
        }
        if (!existHighList.isEmpty() || !existList.isEmpty() || !existSuperList.isEmpty()) {
            queryParam.put("manageDepartment", null);
        }
        dataMap.put("departmentPermission", !ObjectUtils.isEmpty(departmentList) || !ObjectUtils.isEmpty(special));
        boolean viewPermission = !existHighList.isEmpty() || !existList.isEmpty() || !existSuperList.isEmpty() ||
                !ObjectUtils.isEmpty(departmentList) ||
                !ObjectUtils.isEmpty(special);
        dataMap.put("viewPermission", viewPermission);
        if (!viewPermission) {
            return dataMap;
        }
        boolean onlyDepPermission = existHighList.isEmpty() && existList.isEmpty() && existSuperList.isEmpty();
        // 数据初始化
        Map<String, Object> greenData = new HashMap<>();
        Map<String, Object> costData = new HashMap<>();
        greenData.put("greenAmount", 0);
        greenData.put("applyAmount", 0);
        greenData.put("applyRate", 0);
        costData.put("costAmount", 0);
        costData.put("actualAmount", 0);
        costData.put("actualRate", 0);
        dataMap.put("greenData", greenData);
        dataMap.put("costData", costData);
        Map<String, Object> whcData = new HashMap<>();
        whcData.put("budgetAmount", 0);
        whcData.put("costAmount", 0);
        whcData.put("costRate", 0);
        Map<String, Object> cepData = new HashMap<>();
        cepData.put("budgetAmount", 0);
        cepData.put("costAmount", 0);
        cepData.put("costRate", 0);
        dataMap.put("whcData", whcData);
        dataMap.put("cepData", cepData);
        if (type == 1) {
            if (existHighList.isEmpty() && existList.isEmpty() && existSuperList.isEmpty() && !depManage) {
                return dataMap;
            }
            AssetsBudgetYear assetsBudgetYear = assetsBudgetYearDao.getAssetsBudgetByYear(currentYear);
            if (ObjectUtils.isEmpty(assetsBudgetYear)) {
                greenData.put("greenAmount", 0);
                costData.put("costAmount", 0);
            } else {
                greenData.put("greenAmount", assetsBudgetYear.getGreenAmount());
                costData.put("costAmount", assetsBudgetYear.getCostAmount());
            }
            // 查询已申请金额
            Map<String, Object> param = new HashMap<>();
//            param.put("startNum", 0);
//            param.put("pageSize", 1000);
            param.put("applyYear", currentYear);
            List<Assets> assetsList = assetsDao.getAssetsList(param);
            BigDecimal applyAmount = new BigDecimal(0);
            for (Assets assets : assetsList) {
                applyAmount = applyAmount.add(assets.getGreenAmount());
            }
            greenData.put("applyAmount", applyAmount);
            if (ObjectUtils.isEmpty(assetsBudgetYear) || ObjectUtils.isEmpty(assetsBudgetYear.getGreenAmount())) {
                greenData.put("applyRate", 0);
            } else {
                greenData.put("applyRate", applyAmount.multiply(BigDecimal.valueOf(100)).divide(assetsBudgetYear.getGreenAmount(), 2, RoundingMode.HALF_UP));
            }
            dataMap.put("greenData", greenData);

            // 查询已花费金额
            param.put("startNum", 0);
            param.put("pageSize", 100000);
            param.put("year", currentYear);
//            param.put("startDate", "2019-01-01");
//            param.put("endDate", currentYear + "-12-31");
            List<AssetsStatistics> statisticsList = assetsStatisticsDao.pageAssetsStatisticsInfo(param);
            BigDecimal actualAmount = new BigDecimal(0);
            for(AssetsStatistics statistics: statisticsList) {
                actualAmount = DecimalUtils.add(actualAmount,statistics.getActualAmount());
            }
            costData.put("actualAmount", actualAmount);
            if (ObjectUtils.isEmpty(assetsBudgetYear) || ObjectUtils.isEmpty(assetsBudgetYear.getCostAmount())) {
                greenData.put("actualRate", 0);
            } else {
                costData.put("actualRate", actualAmount.multiply(BigDecimal.valueOf(100)).divide(assetsBudgetYear.getCostAmount(), 2, RoundingMode.HALF_UP));
            }
//            if (StringUtils.equals(currentYear, "2023")) {
//                costData.put("actualAmount", 27894252.76);
//                costData.put("actualRate", 95.85);
//            }
            dataMap.put("costData", costData);
        } else if (type == 2) {
//            Map<String, Object> query = new HashMap<>();
//            query.put("year", currentYear);
//            query.put("startNum", 0);
//            query.put("pageSize", 100000);
            queryParam.put("startNum", 0);
            queryParam.put("pageSize", 100000);
            List<ExpenseYearBudget> yearBudgetList = assetsExpenseYearBudgetDao.pageExpenseYearBudgetInfo(queryParam);
            BigDecimal wpcBudget = new BigDecimal(0);
            BigDecimal cepBudget = new BigDecimal(0);
            if (!onlyDepPermission && yearBudgetList.size() > 1) {
                for (ExpenseYearBudget yearBudget : yearBudgetList) {
                    if (StringUtils.equals(yearBudget.getDomain(), "WPC")) {
                        wpcBudget = yearBudget.getAmount();
                    } else if (StringUtils.equals(yearBudget.getDomain(), "CEP")) {
                        cepBudget = yearBudget.getAmount();
                    }
                }
            }

            List<ExpenseOrder> expenseOrderList = assetsExpenseDao.pageAssetsExpenseInfo(queryParam);
            BigDecimal wpcAmount = new BigDecimal(0);
            BigDecimal cepAmount = new BigDecimal(0);

            Map<String, Map<String, String>> projectMap = assetsProjectDao.getAssetsProjectMapBySn();
            Map<String, Map<String, String>> departmentMap = patentDepartmentDao.getDepartmentMap();
            List<ExpenseBudget> budgetList = assetsExpenseBudgetDao.pageExpenseBudgetInfo(queryParam);
            Map<String, BigDecimal> budgetMap = new HashMap<>();
            for (ExpenseBudget budget : budgetList) {
                if(onlyDepPermission) {
                    if (StringUtils.equals(budget.getDomain(), "WPC")) {
                        wpcBudget = DecimalUtils.add(wpcBudget,budget.getAmount());
                    } else if (StringUtils.equals(budget.getDomain(), "CEP")) {
                        cepBudget = DecimalUtils.add(cepBudget,budget.getAmount());
                    }
                }
                String key = budget.getDepartment() + "-" + budget.getDomain();
                budgetMap.put(key, budget.getAmount());
            }
            whcData.put("budgetAmount", wpcBudget);
            cepData.put("budgetAmount", cepBudget);
            Map<String, BigDecimal> departmentAmountMap = new HashMap<>();
            for (ExpenseOrder order : expenseOrderList) {
                if (StringUtils.equals("CEP", order.getDomain())) {
                    cepAmount = DecimalUtils.add(cepAmount, order.getAmount());
                } else {
                    wpcAmount = DecimalUtils.add(wpcAmount, order.getAmount());
                }

                if (StringUtils.isEmpty(order.getProjectNo())) {
                    BigDecimal departmentAmount = new BigDecimal(0);
                    String depKey = order.getDepartment() + "-" + order.getDomain();
                    if (departmentAmountMap.containsKey(depKey)) {
                        departmentAmount = DecimalUtils.add(departmentAmountMap.get(depKey), order.getAmount());
                    } else {
                        departmentAmount = order.getAmount();
                    }
                    departmentAmountMap.put(depKey, departmentAmount);
                } else {
                    if (!projectMap.containsKey(order.getProjectNo())) {
                        BigDecimal departmentAmount = new BigDecimal(0);
                        String depKey = order.getDepartment() + "-" + order.getDomain();
                        if (departmentAmountMap.containsKey(depKey)) {
                            departmentAmount = DecimalUtils.add(departmentAmountMap.get(depKey), order.getAmount());
                        } else {
                            departmentAmount = order.getAmount();
                        }
                        departmentAmountMap.put(depKey, departmentAmount);
                        continue;
                    }
                    String department = projectMap.get(order.getProjectNo().toUpperCase()).get("department");
                    String depKey = department + "-" + order.getDomain();
                    BigDecimal departmentAmount = new BigDecimal(0);
                    if (departmentAmountMap.containsKey(depKey)) {
                        departmentAmount = DecimalUtils.add(departmentAmountMap.get(depKey), order.getAmount());
                    } else {
                        departmentAmount = order.getAmount();
                    }
                    departmentAmountMap.put(depKey, departmentAmount);
                }
            }
            List<Map<String, Object>> departmentAmountList = new ArrayList<>();
            List<Map<String, Object>> departmentAmountCepList = new ArrayList<>();
            if (!departmentAmountMap.isEmpty()) {
                for (String dep : departmentAmountMap.keySet()) {
                    Map<String, Object> item = new HashMap<>();
                    Map<String, String> depInfo = new HashMap<>();
                    String domain = "";
                    if (dep.contains("-")) {
                        List<String> depKeyList = Arrays.asList(dep.split("-"));
                        depInfo = departmentMap.get(depKeyList.get(0));
                        domain = depKeyList.get(1);
//                        item.put("dep", depInfo.get("departmentName") + "-" + domain);
                        item.put("dep", depInfo.get("name"));
                    } else {
                        depInfo = departmentMap.get(dep);
                        item.put("dep", depInfo.get("name"));
                    }
                    item.put("category", "花费");
                    item.put("amount", departmentAmountMap.get(dep));
                    Map<String, Object> itemBudget = new HashMap<>();
                    itemBudget.put("dep", item.get("dep"));
                    itemBudget.put("category", "预算");
                    itemBudget.put("amount", budgetMap.containsKey(dep) ? budgetMap.get(dep) : BigDecimal.ZERO);
                    if (StringUtils.equals("CEP", domain)) {
                        departmentAmountCepList.add(item);
                        departmentAmountCepList.add(itemBudget);
                    } else {
                        departmentAmountList.add(item);
                        departmentAmountList.add(itemBudget);
                    }
                }
                dataMap.put("chartDepDataList", departmentAmountList.stream().sorted(
                                Comparator.comparing((Map<String, Object> h) -> (String) h.get("category")).
                                        thenComparing((Map<String, Object> h) -> (BigDecimal) h.get("amount")).reversed())
                        .collect(Collectors.toList()));
                dataMap.put("chartDepCepDataList", departmentAmountCepList.stream().sorted(
                                Comparator.comparing((Map<String, Object> h) -> (String) h.get("category")).
                                        thenComparing((Map<String, Object> h) -> (BigDecimal) h.get("amount")).reversed())
                        .collect(Collectors.toList()));
            } else {
                dataMap.put("chartDepDataList", new ArrayList<>());
                dataMap.put("chartDepCepDataList", new ArrayList<>());
            }
            whcData.put("costAmount", onlyDepPermission ? 0 : wpcAmount);
            whcData.put("costRate", wpcBudget.equals(BigDecimal.ZERO) ? 0 : wpcAmount.multiply(BigDecimal.valueOf(100)).divide(wpcBudget, 2, RoundingMode.HALF_UP));
            dataMap.put("whcData", whcData);
            cepData.put("costAmount", onlyDepPermission ? 0 : cepAmount);
            cepData.put("costRate", cepBudget.equals(BigDecimal.ZERO) ? 0 : cepAmount.multiply(BigDecimal.valueOf(100)).divide(cepBudget, 2, RoundingMode.HALF_UP));
            dataMap.put("cepData", cepData);
        }
        dataMap.put("onlyDepPermission", onlyDepPermission);
        return dataMap;
    }

    @Override
    public void exportAssetsBudget(HttpServletResponse response) {
        ExcelData data = new ExcelData();
        data.setFileName("固资首页导出excel.xlsx");
//        Map<String, Object> queryParam = new HashMap<>();
//        queryParam.put("startNum", 0);
//        queryParam.put("pageSize", 10000);
//        List<AssetsBudget> assetsBudgetList = assetsBudgetDao.pageAssetsBudget(queryParam);
//        Map<String, Map<String, String>> departmentMap = patentDepartmentDao.getDepartmentMap();
//        Map<String, Map<String, String>> userMap = userDao.getUserMap();
//        String[] head = {"展示排序", "预算号", "申请部门", "项目描述", "项目负责人", "项目类型", "计划申请金额", "计划提交时间", "当年花费", "下一年度花费", "状态"};
//        data.setHead(head);
//        String[][] dataList = new String[assetsBudgetList.size()][head.length];
//        int index = 0;
//        for (AssetsBudget assetsBudget : assetsBudgetList) {
//            dataList[index][0] = String.valueOf(index + 1);
//            dataList[index][1] = assetsBudget.getPlanNo();
//            dataList[index][2] = departmentMap.containsKey(assetsBudget.getDepartment()) ? departmentMap.get(assetsBudget.getDepartment()).get("name") : "";
//            dataList[index][3] = assetsBudget.getProjectName();
//            dataList[index][4] = userMap.containsKey(assetsBudget.getProjectManage()) ? userMap.get(assetsBudget.getProjectManage()).get("name") : "";
//            dataList[index][5] = String.valueOf(assetsBudget.getProjectType());
//            dataList[index][6] = String.valueOf(assetsBudget.getPlanAmount());
//            dataList[index][7] = assetsBudget.getPlanDate();
//            dataList[index][8] = String.valueOf(assetsBudget.getCurrentYearAmount());
//            dataList[index][9] = String.valueOf(assetsBudget.getNextYearAmount());
//            dataList[index][10] = assetsBudget.getStatus() == 1 ? "启用" : "未启用";
//            index++;
//        }
//        data.setData(Arrays.asList(dataList));
        ExcelUtils.exportExcel(response, data);
    }

    @Override
    public Map<String, Object> pageAssetsDepDetail(String year, String department) {
        Map<String, Object> queryParam = new HashMap<>();
        queryParam.put("startNum", 0);
        queryParam.put("pageSize", 100000);
        queryParam.put("department", department);
        List<AssetsProject> projectList = assetsProjectDao.pageAssetsProjectInfo(queryParam);
        List<String> projectIdList = projectList.stream().map(AssetsProject::getProjectNo).collect(Collectors.toList());
        List<ExpenseOrder> projectOrder;
        if (ObjectUtils.isEmpty(projectIdList)) {
            projectOrder = new ArrayList<>();
        } else {
            projectOrder = assetsExpenseDao.getProjectOrderList(year, projectIdList);
        }
        List<ExpenseOrder> departmentOrder = assetsExpenseDao.getDepOrderList(year, department);
        Set<ExpenseOrder> orderSet = new HashSet<>();
        orderSet.addAll(projectOrder);
        orderSet.addAll(departmentOrder);
        Map<String, BigDecimal> depMonth = new HashMap<>();
        for (ExpenseOrder order : orderSet) {
            String monthKey = order.getDomain() + "-" + Integer.valueOf(order.getMonth());
            BigDecimal monthAmount = BigDecimal.ZERO;
            if (depMonth.containsKey(monthKey)) {
                monthAmount = depMonth.get(monthKey);
            }
            monthAmount = DecimalUtils.add(monthAmount, order.getAmount());
            depMonth.put(monthKey, monthAmount);
        }
        Map<String, Object> dataMap = new HashMap<>();
        List<Map<String, Object>> chartYearDataList = new ArrayList<>();
        List<Map<String, Object>> chartYearCepDataList = new ArrayList<>();
        if (!depMonth.isEmpty()) {
            for (String monthKey : depMonth.keySet()) {
                List<String> keyList = Arrays.asList(monthKey.split("-"));
                String domain = keyList.get(0);
                String month = keyList.get(1);
                Map<String, Object> item = new HashMap<>();
                item.put("month", month);
                item.put("category", "花费");
                item.put("amount", depMonth.get(monthKey));
                if (StringUtils.equals(domain, "CEP")) {
                    chartYearCepDataList.add(item);
                    continue;
                }
                chartYearDataList.add(item);
            }
        }
        dataMap.put("chartYearDataList", chartYearDataList.stream().sorted(
                        Comparator.comparing((Map<String, Object> h) -> Integer.valueOf((String) h.get("month"))))
                .collect(Collectors.toList()));
        dataMap.put("chartYearCepDataList", chartYearCepDataList.stream().sorted(
                        Comparator.comparing((Map<String, Object> h) -> Integer.valueOf((String) h.get("month"))))
                .collect(Collectors.toList()));
        return dataMap;
    }
}
